package org.korosoft.rusalad.syncnrun.cli;

import org.apache.commons.cli.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import java.util.HashSet;
import java.util.Set;

/**
 * CLI client-related command. Includes support for such arguments as output level.
 *
 * @author Dmitry Korotkov
 * @since 1.0
 */
public abstract class CliCommand {
    private static final Log log = LogFactory.getLog(CliCommand.class);

    protected final String name;
    protected final String description;
    protected final Options options;

    protected final Set<PreProcessor> preProcessors = new HashSet<PreProcessor>();

    public CliCommand(String name, String description) {
        this.name = name;
        this.description = description;
        options = new Options();
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public Options getOptions() {
        return options;
    }

    protected void addCommonLoggingOpts() {
        options.addOption("v", "verbose", false, "Verbose output");
        options.addOption(null, "silent", false, "Suppress output");
        options.addOption(null, "debug", false, "Debug output");
        preProcessors.add(new PreProcessor() {
            @Override
            public void preProcess(CommandLine commandLine) {
                if (commandLine.hasOption("verbose")) {
                    Logger.getRootLogger().setLevel(Level.DEBUG);
                }

                if (commandLine.hasOption("silent")) {
                    Logger.getRootLogger().setLevel(Level.OFF);
                }

                if (commandLine.hasOption("debug")) {
                    Logger.getRootLogger().setLevel(Level.TRACE);
                }
            }
        });
    }

    public final void execute(String[] args) throws ParseException {
        CommandLineParser parser = new PosixParser();
        CommandLine commandLine = parser.parse(options, args);

        for (PreProcessor p : preProcessors) {
            p.preProcess(commandLine);
        }
        try {
            doExecute(commandLine);
        } catch (Exception e) {
            if (log.isTraceEnabled()) {
                log.trace(e.getMessage(), e);
            } else {
                log.error(e.getMessage());
            }
            log.debug("Exiting with failure");
            System.exit(1);
        }
        System.exit(0);
    }

    protected abstract void doExecute(CommandLine commandLine) throws Exception;

    protected interface PreProcessor {
        void preProcess(CommandLine commandLine);
    }
}
